<template>
  <div class="qr-code" v-loading="loading" :style="{width:`${width}px`,height:`${height}px`,padding:`${padding}px`}">
    <div class="qr-error login-tips" v-if="!hasLogin">
      <el-button size="small" type="primary" @click="$emit('login')">请先登录</el-button>
    </div>
    <div class="qr-error login-tips" v-else-if="!isAgree">
      <el-button size="small" type="primary" @click="isAgree=true">确认协议并支付</el-button>
    </div>
    <div class="code-box"
      v-show="hasLogin">
      <div
        ref="qrCode"
        key="code">
      </div>
      <div v-show="error"
        class="refresh qr-error"
        key="refresh"
        @click="refreshCode">
        <div v-if="error">
          <svg-icon icon-class="code-refresh" />
          <p class="text-error">{{error}}</p>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import QRCode from 'qrcodejs2'
import { createOrderApi, getOrderInfoApi, checkOrderInfo } from './api'
import { debounce } from '@/utils'

export default {
  name: 'LyPaymentCode',
  props: {
    isShow: {
      type: Boolean,
      default: true
    },
    hasLogin: {
      type: Boolean,
      default: false
    },
    needAgree: {
      type: Boolean,
      default: false
    },
    product: {
      type: Object,
      require: true
    },
    otherParamsStr: {
      type: String,
      default: '{}'
    },
    width: {
      type: Number,
      default: 150
    },
    height: {
      type: Number,
      default: 150
    },
    padding: {
      type: Number,
      default: 10
    }
  },
  data () {
    return {
      isOnShow: true,
      loading: false,
      qrcode: null,
      timer: null,
      error: '',
      invalidTime: null,
      isAgree: true,
      oldId: '',
      orderInfo: {},
      otherParamsStrCache: ''
    }
  },
  watch: {
    needAgree: {
      handler (newVal) {
        this.isAgree = !newVal
      },
      immediate: true
    },
    'product.id': {
      handler () {
        if (this.createOrder_) {
          this.createOrder_()
        } else {
          this.createOrder()
        }
      },
      immediate: true
    },
    otherParamsStr () {
      this.createOrder_()
    },
    'isShow' () {
      this.createOrder_()
    },
    'hasLogin' () {
      this.createOrder_()
    },
    isAgree () {
      this.createOrder_()
    }
  },
  mounted () {
    const container = this.$refs.qrCode
    this.qrcode = new QRCode(container, {
      text: this.text,
      width: this.width - this.padding * 2,
      height: this.height - this.padding * 2,
      colorDark: '#000000',
      colorLight: '#ffffff',
      correctLevel: 0
    })
  },
  activated () {
    this.isOnShow = true
    this.createOrder()
  },
  deactivated () {
    this.isOnShow = false
    this.createOrder()
  },
  beforeDestroy () {
    this.isOnShow = false
    this.createOrder()
  },
  async created () {
    this.createOrder_ = debounce(() => {
      this.createOrder()
    }, 250, false)

    this.$xzReg('xz_360_pay_res', (res) => {
      this.dealPayRes(res)
    })
  },
  methods: {
    refreshCode () {
      this.$emit('refresh')
      this.clearOrder()
      this.createOrder()
    },
    setTime (oldCode) {
      clearTimeout(this.timer)
      if (this.invalidTime < Date.now()) {
        this.error = '二维码已过期'
        this.emitOrderStatus('timeout')
        return
      }

      this.timer = setTimeout(() => {
        if (this.error || oldCode !== this.product.orderid) {
          return
        }

        oldCode = this.product.orderid
        checkOrderInfo({
          orderid: this.product.orderid,
          sign: this.product.sign,
          type: '360'
        }).then(res => {
          if (oldCode !== this.product.orderid) {
            return
          }

          const data = res.data || {}
          if (data.status === 0) {
            this.emitOrderStatus('succes')
          } else if (data.status === 2) {
            this.error = '订单无效！'
            this.emitOrderStatus('error')
          }
          this.setTime(oldCode)
        }).catch(() => {
          this.setTime(oldCode)
        })
      }, 3000)
    },
    async createOrder () {
      if (!this.$store.getters.appInfo.channel) {
        await this.$store.dispatch('user/getUserInfo')
      }

      clearTimeout(this.timer)
      if ([!this.isOnShow, !this.hasLogin, !this.isAgree, !this.product.id].includes(true)) return
      if (this.product.orderid && this.product.otherParamsStr === this.otherParamsStr) {
        const invalidTime = this.product.payURLExpireTime
        if (invalidTime > Date.now()) {
          this.makePayCode()
          return
        }
      }

      const params = {
        product_id: [this.product.id],
        pay_way: 8, // 360
        pay_entry: 'web',
        channel_id: this.$store.getters.appInfo.channel
      }

      const otherParamsStr = this.otherParamsStr
      this.otherParamsStrCache = otherParamsStr
      const otherParams = JSON.parse(otherParamsStr)

      if (otherParams.noproduct) {
        params.product_id = []
      }
      if (otherParams.couponid) {
        params.coupon_id = otherParams.couponid
      }
      if (otherParams.actids) {
        const ids = otherParams.actids.split(',')
        params.act_ids = ids.map(id => parseInt(id))
      }
      if (otherParams.giveproduct) {
        params.give_product = otherParams.giveproduct
      }
      if (otherParams.addproduct) {
        params.add_product_id = otherParams.addproduct
      }
      if (otherParams.quantity) {
        params.quantity = parseInt(otherParams.quantity)
        params.act_fixed_id = otherParams.act_fixed_id
      }

      this.loading = true
      createOrderApi(params).then(res => {
        this.oldId = params.product_id[0] || this.product.id
        if (this.product.id !== this.oldId) {
          this.loading = false
          return
        }
        this.orderInfo = res.data
        this.getOrderInfo()
      }).catch(() => {
        this.setCodeError()
      })
    },
    dealPayRes (res) {
      this.loading = false
      if (this.product.id !== this.oldId) {
        return
      }

      this.error = ''
      this.product.payURL = res.wszQrCode
      this.product.orderid = this.orderInfo.order_id
      this.product.sign = this.orderInfo.sign
      this.product.otherParamsStr = this.otherParamsStrCache
      this.product.payURLExpireTime = Number(res.tExpireTime) * 1000
      this.makePayCode()
    },
    getOrderInfo () {
      if (!this.orderInfo.order_id) {
        this.setCodeError()
        return
      }

      const orderInfo = {
        type: this.orderInfo.pay_way_str,
        orderid: this.orderInfo.order_id,
        sign: this.orderInfo.sign,
        title: this.orderInfo.title,
        appID: process.env.VUE_APP_ID,
        trade_method: 'APP',
        payAppId: this.$xz('xz_get_payAppId') || 'DPHwqz80'
      }

      // 调起订单支付
      getOrderInfoApi(orderInfo).then(async (res) => {
        // 360支付
        const params = JSON.parse(res.data.prepayInfo.param)
        Object.keys(params).forEach(key => (params[key] = `${params[key]}`))

        // pay结果在 dealPayRes 中处理
        const payBool = await this.$xzAsy('xz_360_pay', params)

        if (!payBool) {
          this.setCodeError()
        }
      }).catch(() => {
        this.setCodeError()
      })
    },
    setCodeError () {
      this.error = '请刷新二维码'
      this.loading = false
    },
    makePayCode () {
      const payURL = this.product.payURL
      this.invalidTime = this.product.payURLExpireTime
      if (this.qrcode) {
        this.qrcode.makeCode(payURL)
        this.qrcode._el.title = ''
        this.setTime(this.product.orderid)
      }
    },
    clearOrder () {
      this.product.payURL = null
      this.product.orderid = null
      this.product.sign = null
      this.product.otherParamsStr = null
      this.product.payURLExpireTime = null
    },
    emitOrderStatus (status) {
      this.clearOrder()
      this.$emit('onStatusChange', status)
    }
  }
}
</script>
<style lang="scss" scoped>
@import "./index.scss";
</style>
